/*
 * Copyright 2020-2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ace.module.oauth2.server.core.impl.authorization.token;

import java.time.Instant;
import java.util.Base64;
import org.springframework.lang.Nullable;
import org.springframework.security.crypto.keygen.Base64StringKeyGenerator;
import org.springframework.security.crypto.keygen.StringKeyGenerator;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;

/**
 * An {@link OAuth2TokenGenerator} that generates an {@link OAuth2RefreshToken}.
 * 根据token格式类型 {@link OAuth2TokenFormat} 生成对应的 token value格式 {@link Oauth2StringKeyUUIDGenerator} 与 {@link Base64StringKeyGenerator}
 * @author Caspar
 * @see OAuth2TokenGenerator
 * @see OAuth2RefreshToken
 */
public class Oauth2RefreshTokenGenerator implements OAuth2TokenGenerator<OAuth2RefreshToken> {
  private final StringKeyGenerator refreshTokenGenerator = new Oauth2StringKeyUUIDGenerator();
  private final StringKeyGenerator refreshTokenBase64Generator =
      new Base64StringKeyGenerator(Base64.getUrlEncoder().withoutPadding(), 96);

  @Nullable
  @Override
  public OAuth2RefreshToken generate(OAuth2TokenContext context) {
    if (!OAuth2TokenType.REFRESH_TOKEN.equals(context.getTokenType())) {
      return null;
    }
    String refreshToken = this.generateRefreshToken(context);
    Instant issuedAt = Instant.now();
    Instant expiresAt =
        issuedAt.plus(context.getRegisteredClient().getTokenSettings().getRefreshTokenTimeToLive());
    return new OAuth2RefreshToken(refreshToken, issuedAt, expiresAt);
  }

  private String generateRefreshToken(OAuth2TokenContext context) {
    if (OAuth2TokenFormat.SELF_CONTAINED.equals(
        context.getRegisteredClient().getTokenSettings().getAccessTokenFormat())) {
      return this.refreshTokenBase64Generator.generateKey();
    } else {
      return this.refreshTokenGenerator.generateKey();
    }
  }
}
